package com.tg.app;

import static com.appbase.custom.config.TGConfig.APP_ID;
import static com.appbase.custom.config.TGConfig.TEST_APP_ID;

import android.app.Application;
import android.content.Context;
import android.net.ParseException;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;

import androidx.core.util.Consumer;

import com.appbase.custom.app.LOGIN_STATUS;
import com.appbase.custom.constant.CommonConstants;
import com.inuker.bluetooth.library.BluetoothContext;
import com.tange.ai.core.router.core.Router;
import com.tange.base.toolkit.GlobalApplicationContext;
import com.tange.base.toolkit.PreferenceUtil;
import com.tange.base.toolkit.StringUtils;
import com.tange.core.access.token.Authentication;
import com.tange.core.access.token.Error;
import com.tange.core.backend.service.auth.OnUnauthorizedListener;
import com.tange.core.backend.service.auth.UnauthorizedDispatcher;
import com.tange.core.backend.service.ep.Env;
import com.tange.core.backend.service.ep.Environment;
import com.tange.core.backend.service.http.ClientObserver;
import com.tange.core.backend.service.http.HttpConfigurations;
import com.tange.core.backend.service.interceptor.HttpLoggingInterceptor;
import com.tange.core.initialization.Configurations;
import com.tange.core.initialization.TGCore;
import com.tange.core.message.distribution.Message;
import com.tange.core.message.distribution.PersistentConnectionMessage;
import com.tange.core.trouble.shooting.logging.UploadFrequentlyControl;
import com.tange.module.core.wifi.scan.AccessPointScanImpl;
import com.tange.module.core.wifi.scan.ApScanConfiguration;
import com.tange.module.core.wifi.scan.DeviceAccessPointNameStitching;
import com.tange.module.core.wifi.scan.WiFiScanManager;
import com.tange.module.qrcode.scan.QrCodeBitmap;
import com.tange.module.qrcode.scan.QrCodeBitmapImpl;
import com.tange.module.qrcode.scan.QrCodeRecognitionFactoryImpl;
import com.tange.module.qrcode.scan.QrCodeRecognitionHub;
import com.tange.module.socket.SocketIoConstants;
import com.tange.module.socket.SocketIoManager;
import com.tencent.bugly.crashreport.CrashReport;
import com.tg.app.helper.ModuleImpl;
import com.tg.app.util.ObjectBoxUtil;
import com.tg.appcommon.android.DensityUtils;
import com.tg.appcommon.android.LanguageUtils;
import com.tg.appcommon.android.TGApplicationBase;
import com.tg.appcommon.android.TGLog;
import com.tg.appcommon.android.TGResources;
import com.tg.appcommon.app.AppLifecycleCallbacks;
import com.tg.appcommon.helper.LogoutDialogHelper;
import com.tg.appcommon.router.TGModuleRouter;
import com.tg.appcommon.sdk.TGErrorCode;
import com.tg.data.http.entity.UserInfo;
import com.tg.data.media.MediaDecoderConfig;
import com.tg.loginex.helper.UserProtocolHelper;
import com.tg.network.socket.http.TGHttp;
import com.tg.push.PushManager;
import com.umeng.analytics.MobclickAgent;
import com.umeng.commonsdk.UMConfigure;

import org.json.JSONException;

import java.lang.ref.WeakReference;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.plugins.RxJavaPlugins;
import io.reactivex.schedulers.Schedulers;
import retrofit2.HttpException;

public class TGSdkHelper {
    private static final String TAG = "TGSdkHelperTAG";
    public static final String SP_PRE_LOG_ENABLE = "com.tg.app.SP_PRE_LOG_ENABLE";
    public static final String SP_PRE_CHOSE_API_ENV = "com.tg.app.SP_PRE_CHOSE_API_ENV";
    private String mAppId;
    private String mToken;
    private String mUserId;
    private boolean mInitSdk = false;
    private WeakReference<TGSdk.TGNotifyListener> mTGNotifyListener;
    private static boolean isCloudPushInit = false;
    public boolean isInitSdk() {
        return mInitSdk;
    }
    public String getToken() {
        return mToken;
    }
    public boolean isThirdPartyApp(){
        return !StringUtils.isEmpty(mAppId);
    }
    public String getAppId() {
        return mAppId;
    }

    @Deprecated
    public void notifyThirdPartyApp(int messageId, String messageInfo){
        if (mTGNotifyListener != null && mTGNotifyListener.get() != null){
            mTGNotifyListener.get().onNotify(messageId, messageInfo);
        }
    }

    @Deprecated
    public void checkToken(String appId, String token, String userId, TGSdk.InitSdkListener listener){
        mAppId = appId;
        mToken = token;
        HttpConfigurations.getInstance().setUserToken(mToken);
        TGApplicationBase.getInstance().putGlobalObject(TGApplicationBase.APP_TOKEN, mToken);
        mUserId = userId;
        HashMap<String, String> map = new HashMap<>();
        map.put("appid", appId);
        map.put("token", token);
        TGHttp.getInstance().checkToken(map)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new ClientObserver<UserInfo>() {
                    @Override
                    protected void onSuccess(UserInfo content) {
                        TGLog.d(TAG, "LoginBean = " + content);
                        mInitSdk = true;
                        mUserId = content.user_id;
                        int userID = Integer.parseInt(content.user_id);
                        HttpConfigurations.getInstance().setAppId(mAppId);
                        PreferenceUtil.setString(TGApplicationBase.getApplicationContext(),CommonConstants.THIRD_PARTY, mAppId);
                        PreferenceUtil.setString(TGApplicationBase.getApplicationContext(),CommonConstants.PRE_TOKEN, mToken);
                        HttpConfigurations.getInstance().setUserToken(mToken);
                        PreferenceUtil.setInt(TGApplicationBase.getApplicationContext(), CommonConstants.PRE_USER_ID, userID);
                        TGLog.i(TAG, "sdk token :" + mToken); //user_id，openapi_user
                        if (listener != null){
                            listener.onResult(true, TGErrorCode.ERROR_SUCCESS, "");
                        }
                    }

                    @Override
                    protected void onResponseError(int errorCode, String errorInfo) {
                        TGLog.d(TAG, "errorInfo = " + errorInfo);
                        if (listener != null){
                            listener.onResult(false, errorCode, errorInfo);
                        }
                    }

                    @Override
                    protected void onOtherError(String error) {
                        TGLog.d(TAG, "error" + error);
                        if (listener != null){
                            listener.onResult(false, TGErrorCode.ERROR_LOCAL_OTHER, error);
                        }
                    }
                });
    }



    private final AppLifecycleCallbacks.ActivityStartListener mActivityStartListener = () -> {
        if (LogoutDialogHelper.getInstance().isMustDialog()) {
            LogoutDialogHelper.getInstance().showLogoutDialog(LogoutDialogHelper.getInstance().getDiaLogParam());
        }
    };

    public void onConfigurationChanged(Context context) {
        HttpConfigurations.getInstance().setLanguage(LanguageUtils.getLanguage(context));
    }

    public static Env currentEnv(Application application) {
        String preChoseEnvName = Env.PRODUCT.name();
        Env preChoseEnv = Env.PRODUCT;
        try {
            preChoseEnv = Env.valueOf(preChoseEnvName);
        } catch (Throwable ex) {
            preChoseEnv = Env.PRODUCT;
            TGLog.i(TAG, "[initApp][env-setting] error while parse : " + ex);
        }
        TGLog.i(TAG, "[initApp][env-setting] preChoseEnv : " + preChoseEnv);

        return preChoseEnv;
    }

    public void initApp(Application application, TGSdk.TGNotifyListener listener, boolean log){

        TGApplicationBase.init(application);

        final boolean debugModeEnabled = BuildConfig.DEBUG || PreferenceUtil.getBoolean(application, SP_PRE_LOG_ENABLE, false);

        TGLog.i(TAG, "[initApp] debugModeEnabled = " + debugModeEnabled);

        Environment.INSTANCE.enableDebugMode(false);
        Env env = BuildConfig.DEBUG? Env.TEST : Env.PRODUCT;

        Configurations configurations = new Configurations.Builder(application)
                .setAppId(APP_ID)
                .setLanguage(LanguageUtils.getLanguage(application))
                .setGoogleChannel(false)
                .enableDebugMode(true)
                .setEnvironment(Env.TEST)
                .build();

        BluetoothContext.set(application);
        TGCore.INSTANCE.initialize(configurations);


        // 自己的OEM APP，不限制日志的上传频率
        UploadFrequentlyControl.INSTANCE.setENABLE(false);


        HttpLoggingInterceptor.enableLogging = true;

        // 启动后先沿用上次的登录态，登录成功后再刷新
        String token = PreferenceUtil.getString(application, CommonConstants.PRE_TOKEN);
        if (!TextUtils.isEmpty(token)) {
            int userId = PreferenceUtil.getInt(application, CommonConstants.PRE_USER_ID);
            HttpConfigurations.getInstance().setUserId(userId);
            HttpConfigurations.getInstance().setUserToken(token);
        }

        Router.INSTANCE.setLogger((tag, msg) -> TGLog.i("Router##" + tag, msg));
        boolean supportAiSound = PreferenceUtil.getBoolean(TGApplicationBase.getApplicationContext(), CommonConstants.PRE_SETTINGS_AI_SOUND,false);
        MediaDecoderConfig.getInstance().setUseAudioAIDecoder(supportAiSound);
        mTGNotifyListener = new WeakReference<>(listener);
        MediaDecoderConfig.getInstance().setUseFFmpegRecorder(true);

        PushManager.setGooglePlayChannel(BuildConfig.IS_GOOGLE_PLAY);
        PushManager.setIntegratedWithFcm(BuildConfig.IS_FCM_ON);
        WiFiScanManager.setWiFiScan(new AccessPointScanImpl());
        QrCodeRecognitionHub.register(new QrCodeRecognitionFactoryImpl());
        QrCodeBitmap.setQrCodeBitmapImpl(new QrCodeBitmapImpl());

        ApScanConfiguration.INSTANCE.configure(BuildConfig.DEVICE_AP_PREFIX);
        // 自定义UUID转成 完成AP名称 的转换规则
        DeviceAccessPointNameStitching.INSTANCE.setTransform(deviceId -> {
            if (deviceId.startsWith(BuildConfig.DEVICE_AP_PREFIX)) return deviceId;
            else return BuildConfig.DEVICE_AP_PREFIX + "_" + deviceId;
        });

        TGLog.i(TAG, "[initApp] apNamePrefix = " + ApScanConfiguration.INSTANCE.apNamePrefix());
        TGLog.i(TAG, "[initApp] apNamePrefixEndsWithUnderLine = " + ApScanConfiguration.INSTANCE.apNamePrefixEndsWithUnderLine());

        TGModuleRouter.getInstance().register(ModuleImpl.sImpl);


        application.registerActivityLifecycleCallbacks(TGApplicationBase.getAppLifecycleCallbacks());
        TGApplicationBase.getAppLifecycleCallbacks().setActivityStartListener(mActivityStartListener);
        DensityUtils.setDensity(application);
        boolean isAgree = UserProtocolHelper.isAgreeProtocol(application);

        Thread thread =  new Thread(() -> {
            Looper.prepare();
            ObjectBoxUtil.init(application);
            if (isAgree){
         //       SpeechHelper.createUtility(application, BuildConfig.APP_ID_SPEECH);
            }
            Looper.loop();
        });
        thread.setName("application_init_thread");
        thread.start();

        if (isAgree){
            UMConfigure.init(application, null,null, UMConfigure.DEVICE_TYPE_PHONE, null);
            CrashReport.UserStrategy strategy = new CrashReport.UserStrategy(application);
            strategy.setCrashHandleCallback(new CrashReport.CrashHandleCallback() {
                public Map<String, String> onCrashHandleStart(int crashType, String errorType,
                                                              String errorMessage, String errorStack) {

                    TGLog.i(TAG,"[APP-CRASH] crashType = " + crashType);
                    TGLog.i(TAG,"[APP-CRASH] errorType = " + errorType);
                    TGLog.i(TAG,"[APP-CRASH] errorMessage = " + errorMessage);
                    TGLog.i(TAG,"[APP-CRASH] errorStack = \n" + errorStack);
                    TGLog.flush(true);

                    return CrashReportExtraMessageBuilder.get();
                }

            });
            CrashReport.initCrashReport(application,strategy);
            CrashReport.putUserData(application, "gitVersion", CrashReportExtraMessageBuilder.gitVersion());
        }else {
            UMConfigure.preInit(application,null,null);
        }


        MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.AUTO);
        UMConfigure.setProcessEvent(true);
        UMConfigure.setLogEnabled(BuildConfig.DEBUG);

        if (isAgree) {
            TGCore.INSTANCE.initializeOnUserProtocolAgreed(application);
        } else {
            TGLog.i(TAG, "should NOT get hub info !");
        }



        /** 仅开发模式下，开启布局运行时切换功能 */
        TGResources.setRedirectEnabled(true);

        if (!BuildConfig.DEBUG) {
            // 非测试版本，设置个Handler捕获异常
            RxJavaPlugins.setErrorHandler(throwable -> {
                try {
                    TGLog.i(TAG, "[RxJavaError] " + Log.getStackTraceString(throwable));
                } catch (Throwable ex) {
                    TGLog.i(TAG, "[RxJavaError] " + throwable);
                }
            });
        }

        // 将HTTP异常转化为可读性的文案
        ClientObserver.setHttpErrorLabelTransform(e -> {
            String errorMsg = e.getMessage();

            if (e instanceof UnknownHostException || e instanceof ConnectException) {
                errorMsg = GlobalApplicationContext.application().getResources().getString(R.string.login_error_tips_network_not_ok);
                TGLog.matTrackCustomKVEvent(GlobalApplicationContext.application(),"net_status",e.getMessage());
            } else if (e instanceof SocketTimeoutException) {
                errorMsg = TGApplicationBase.getApplicationContext().getResources().getString(R.string.login_error_tips_network_timeout);
                TGLog.matTrackCustomKVEvent(GlobalApplicationContext.application(),"net_status",e.getMessage());
            } else if (e instanceof HttpException) {
                HttpException httpException = (HttpException) e;
                errorMsg = convertStatusCode(httpException);
            } else if (e instanceof ParseException || e instanceof JSONException) {
                errorMsg = TGApplicationBase.getApplicationContext().getResources().getString(R.string.login_error_tips_data_parse_error);
                TGLog.matTrackCustomKVEvent(GlobalApplicationContext.application(),"data_error",e.getMessage());
            }

            if (TextUtils.isEmpty(errorMsg)) {
                errorMsg = e.toString();
            }

            return errorMsg;
        });


        TGLog.d(TAG, "Token 检测");
        // 全局监听用户令牌失效的状态
        Authentication.INSTANCE.observeOnVerificationFailed(new Consumer<Error>() {
            @Override
            public void accept(Error error) {
                TGLog.d(TAG, "Token失效，请刷新！" + error.getMessage() + ", codee = " + error.getCode());
                TGLog.i(TAG, "[onUnauthorized] ");
                TGApplicationBase.getInstance().onLoginStatusChange(LOGIN_STATUS.STATUS_LOGOUT);
                SocketIoManager.destroyConnection(TGApplicationBase.getApplicationContext());
                PreferenceUtil.setString(TGApplicationBase.getApplicationContext(), CommonConstants.LAST_LOGIN_CHANNEL, "");
                if (401 == error.getCode()){
                    LogoutDialogHelper.getInstance().showLogoutDialog(null);
                }
            }
        });

        PersistentConnectionMessage.INSTANCE.observe(new Consumer<Message>() {
            @Override
            public void accept(Message message) {

                String msg = message.getName();
                String type = message.getParam();

                TGLog.d(TAG, "PersistentConnectionMessage msg = " + msg + ", type = " + type);
                if (SocketIoConstants.NOTIFY_DEVICE_REMOTE_LOGIN.equalsIgnoreCase(type)) {
                    LogoutDialogHelper.getInstance().showLogoutDialog(null);
                }

            }
        });

        HttpLoggingInterceptor.enableLogging = true;
        TGLog.setDebug(true);
        TGLog.setLogLevel(application, TGLog.TYPE_VERBOSE);
    }

    private String convertStatusCode(HttpException httpException) {
        String msg;
        if (httpException.code() == 401) {
            TGLog.d(TAG, "convertStatusCode 401");
            msg = TGApplicationBase.getApplicationContext().getResources().getString(R.string.login_error_tips_need_login);
        } else if (httpException.code() >= 500 && httpException.code() < 600) {
            msg = TGApplicationBase.getApplicationContext().getResources().getString(R.string.login_error_tips_server_error);
        } else if (httpException.code() >= 400 && httpException.code() < 500) {
            msg = TGApplicationBase.getApplicationContext().getResources().getString(R.string.login_error_tips_server_can_not_used);
        } else if (httpException.code() >= 300 && httpException.code() < 400) {
            msg = TGApplicationBase.getApplicationContext().getResources().getString(R.string.login_error_tips_server_request_redirected);
        } else {
            msg = "Error: " + httpException.message();
        }
        return msg;
    }

    private void initRuntimeLogging(Application application, boolean log) {

    }
}
